Skip to content

experimental(agent): Add experimental coding-agent adapters with NeMo-Relay telemetry#1995

Merged
rapids-bot[bot] merged 32 commits into
NVIDIA:developfrom
yczhang-nv:codex/nat-292-code-agent-adapter
Jun 4, 2026
Merged

experimental(agent): Add experimental coding-agent adapters with NeMo-Relay telemetry#1995
rapids-bot[bot] merged 32 commits into
NVIDIA:developfrom
yczhang-nv:codex/nat-292-code-agent-adapter

Conversation

@yczhang-nv

@yczhang-nv yczhang-nv commented May 29, 2026

Copy link
Copy Markdown
Contributor

Description

Adds experimental NVIDIA NeMo Agent Toolkit workflow adapters for five coding-agent harnesses:

  • Claude Code
  • Codex
  • Cursor
  • Hermes
  • OpenClaw

Each adapter is packaged as an installable example with a nat.components entry point, a primitive workflow _type, Relay-enabled configs, Phoenix tracing configs, smoke eval configs, and README guidance.

This also adds an experimental Relay telemetry bridge used by the Relay-backed adapters, plus Phoenix trace screenshots for the verified workflows.

By Submitting this PR I confirm:

  • I am familiar with the Contributing Guidelines.
  • We require that all contributors "sign-off" on their commits. This certifies that the contribution is your original work, or you have rights to submit it under the same license, or a compatible license.
    • Any contribution which contains commits that are not Signed-Off will not be accepted.
  • When the PR is ready for review, new or existing tests cover these changes.
  • When the PR is ready for review, the documentation is up to date with these changes.

Summary by CodeRabbit

  • New Features

    • Added five experimental agent adapter examples: Claude Code, Codex, Cursor, Hermes, and OpenClaw for extended workflow integration scenarios.
    • Introduced relay telemetry bridge for mapping NeMo Relay telemetry events into NAT intermediate steps.
    • Added comprehensive configuration templates and evaluation datasets for each adapter.
  • Documentation

    • Added setup and usage documentation for all experimental agent adapters with end-to-end workflow examples.
  • Tests

    • Added telemetry bridge tests covering event mapping, parentage resolution, and file injection.
  • Chores

    • Updated path checking rules and project dependencies for new experimental examples.

Signed-off-by: Yuchen Zhang <yuchenz@nvidia.com>
@yczhang-nv yczhang-nv self-assigned this May 29, 2026
@yczhang-nv yczhang-nv added feature request New feature or request non-breaking Non-breaking change DO NOT MERGE PR should not be merged; see PR for details labels May 29, 2026
@coderabbitai

coderabbitai Bot commented May 29, 2026

Copy link
Copy Markdown

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

Walkthrough

This PR introduces five experimental agent adapters for the NeMo Agent Toolkit, integrating with NeMo Relay for telemetry collection. It adds Claude Code, Codex, Cursor, Hermes, and OpenClaw workflow adapters, a relay telemetry conversion module, example configurations, comprehensive documentation, and repository wiring updates.

Changes

Experimental Agent Adapters with Relay Integration

Layer / File(s) Summary
Relay telemetry bridge infrastructure
packages/nvidia_nat_core/src/nat/experimental/relay_telemetry_bridge.py, packages/nvidia_nat_core/tests/nat/experimental/test_relay_telemetry_bridge.py
Relay ATOF JSONL events are loaded and converted to NAT IntermediateStep objects by mapping scope start/end and mark events, correlating timestamps and parent UUIDs, extracting usage/metadata, and injecting into the active context. Tests verify parentage wiring, timestamp alignment, custom span creation, and malformed-line handling.
Claude Code agent adapter
examples/experimental/claude_code_agent_adapter/pyproject.toml, examples/experimental/claude_code_agent_adapter/src/nat_claude_code_agent_adapter/__init__.py, examples/experimental/claude_code_agent_adapter/src/nat_claude_code_agent_adapter/register.py, examples/experimental/claude_code_agent_adapter/configs/*, examples/experimental/claude_code_agent_adapter/data/eval-smoke.json, examples/experimental/claude_code_agent_adapter/README.md
Registers claude_code_agent workflow supporting permission modes, model selection, budget limits, and relay-wrapped execution. Generates relay config, manages ATOF event injection, and clips output. Includes three example configs (relay, relay-phoenix, relay-phoenix-eval), data pointer, package metadata, and complete README with integration flow, installation, run, Phoenix, and evaluation documentation.
Codex agent adapter
examples/experimental/codex_agent_adapter/pyproject.toml, examples/experimental/codex_agent_adapter/src/nat_codex_agent_adapter/__init__.py, examples/experimental/codex_agent_adapter/src/nat_codex_agent_adapter/register.py, examples/experimental/codex_agent_adapter/configs/*, examples/experimental/codex_agent_adapter/data/eval-smoke.json, examples/experimental/codex_agent_adapter/README.md
Registers codex_agent workflow with sandbox, approval, and web-search configuration. Runs via NeMo Relay with optional OPENAI_API_KEY removal for ChatGPT auth preference. Injects ATOF telemetry on completion or timeout. Includes relay, relay-phoenix, and relay-phoenix-eval configs, data file, package setup, and detailed README covering Codex CLI setup, relay execution, Phoenix tracing, and evaluation.
Cursor agent adapter
examples/experimental/cursor_agent_adapter/pyproject.toml, examples/experimental/cursor_agent_adapter/src/nat_cursor_agent_adapter/__init__.py, examples/experimental/cursor_agent_adapter/src/nat_cursor_agent_adapter/register.py, examples/experimental/cursor_agent_adapter/configs/*, examples/experimental/cursor_agent_adapter/data/eval-smoke.json, examples/experimental/cursor_agent_adapter/README.md
Registers cursor_agent workflow managing plan mode, sandbox, and workspace trust settings via relay. Patches/restores .cursor/hooks.json for relay integration. Provides detailed error hints for missing auth, workspace trust, or sandbox issues. Includes three example configs, data file, package configuration, and comprehensive README with Cursor setup, relay execution, event inspection, Phoenix integration, and evaluation instructions.
Hermes agent adapter
examples/experimental/hermes_agent_adapter/pyproject.toml, examples/experimental/hermes_agent_adapter/src/nat_hermes_agent_adapter/__init__.py, examples/experimental/hermes_agent_adapter/src/nat_hermes_agent_adapter/register.py, examples/experimental/hermes_agent_adapter/configs/*, examples/experimental/hermes_agent_adapter/data/eval-smoke.json, examples/experimental/hermes_agent_adapter/README.md
Registers hermes_agent workflow running via uvx --from hermes-agent hermes through NeMo Relay. Cleans stdout by removing trailing session_id: lines and provides empty-output diagnostics with Hermes setup/auth/model hints. Injects ATOF events and handles timeouts. Includes relay, relay-phoenix, and relay-phoenix-eval configs, data file, package setup, and full README covering Hermes configuration, relay setup, raw event inspection, Phoenix tracing, and evaluation.
OpenClaw agent adapter
examples/experimental/openclaw_agent_adapter/pyproject.toml, examples/experimental/openclaw_agent_adapter/src/nat_openclaw_agent_adapter/__init__.py, examples/experimental/openclaw_agent_adapter/src/nat_openclaw_agent_adapter/register.py, examples/experimental/openclaw_agent_adapter/configs/*, examples/experimental/openclaw_agent_adapter/data/eval-smoke.json, examples/experimental/openclaw_agent_adapter/README.md
Registers openclaw_agent workflow with agent/session/model configuration and Codex app-server policy forwarding via OPENCLAW_* environment variables. Attempts JSON extraction from output with text fallback. Provides diagnostic hints for OpenClaw/Gateway/Codex configuration errors. Includes relay, relay-phoenix, and relay-phoenix-eval configs, data file, package wiring, and extensive README covering Gateway installation/config, plugin linking, ATIF/OpenInference setup, operational procedures, example runs, Phoenix visualization, and troubleshooting.
Root configuration and documentation
.gitignore, examples/README.md, pyproject.toml
Adds node_modules/ to git ignore. Updates examples index with new Experimental section listing all five adapters with difficulty badges. Registers all four adapters as editable sources in root pyproject.toml.
CI path-check updates
ci/scripts/path_checks.py
Allowlists adapter evaluation configs to reference sibling data files, ignores package-lock.json, and skips node_modules under codex adapter, NeMo-Flow checkouts, and .cursor/.claude developer config directories.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 3.64% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly describes the main objective of the PR - adding experimental coding-agent adapters with NeMo-Relay telemetry integration. However, it exceeds the recommended ~72 character limit at 85 characters.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Comment @coderabbitai help to get the list of available commands and usage tips.

…ration

Signed-off-by: Yuchen Zhang <yuchenz@nvidia.com>
@yczhang-nv yczhang-nv changed the title experimental(agent): Add experimental Claude Code SDK agent example experimental(agent): Add coding agent workflow adapters May 29, 2026
Signed-off-by: Yuchen Zhang <yuchenz@nvidia.com>
Signed-off-by: Yuchen Zhang <yuchenz@nvidia.com>
Signed-off-by: Yuchen Zhang <yuchenz@nvidia.com>
Signed-off-by: Yuchen Zhang <yuchenz@nvidia.com>
Signed-off-by: Yuchen Zhang <yuchenz@nvidia.com>
Signed-off-by: Yuchen Zhang <yuchenz@nvidia.com>
Signed-off-by: Yuchen Zhang <yuchenz@nvidia.com>
Signed-off-by: Yuchen Zhang <yuchenz@nvidia.com>
@yczhang-nv yczhang-nv marked this pull request as ready for review June 3, 2026 00:56
@yczhang-nv yczhang-nv requested review from a team as code owners June 3, 2026 00:56
@coderabbitai coderabbitai Bot removed the DO NOT MERGE PR should not be merged; see PR for details label Jun 3, 2026
@yczhang-nv yczhang-nv changed the title experimental(agent): Add coding agent workflow adapters experimental(agent): Add experimental coding-agent adapters with NeMo-Relay telemetry Jun 3, 2026
…de-agent-adapter

Signed-off-by: Yuchen Zhang <yuchenz@nvidia.com>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 11

🧹 Nitpick comments (4)
packages/nvidia_nat_core/tests/nat/experimental/test_relay_telemetry_bridge.py (1)

124-145: ⚡ Quick win

Consider a negative-path test for malformed JSONL.

Once load_atof_jsonl is hardened to skip bad lines, add a case writing a partial/invalid line to confirm valid events are still loaded. This guards the Relay timeout injection path.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@packages/nvidia_nat_core/tests/nat/experimental/test_relay_telemetry_bridge.py`
around lines 124 - 145, Add a negative-path test that writes a JSONL file
containing both a valid event and a malformed/partial line, then call
load_atof_jsonl and inject_atof_jsonl to verify the loader skips the bad line
and only returns/injects the valid event: create a file with one well-formed
event JSON and one broken line, assert load_atof_jsonl(path) returns only the
valid event, subscribe to Context.intermediate_step_manager, call
inject_atof_jsonl(path, context=...), and assert the captured
IntermediateStep(s) correspond only to the valid event (check event types,
parent_id, and count).
packages/nvidia_nat_core/src/nat/experimental/relay_telemetry_bridge.py (1)

66-83: 💤 Low value

Docstring style: prefer Google-style.

The docstring uses NumPy-style Parameters\n---------- sections. As per coding guidelines, "Provide Google-style docstrings for every public module, class, function and CLI command" (i.e. an Args: section).

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/nvidia_nat_core/src/nat/experimental/relay_telemetry_bridge.py`
around lines 66 - 83, The docstring for relay_events_to_intermediate_steps uses
NumPy-style Parameters/---------- formatting; update it to a Google-style
docstring: replace the Parameters section with an Args: block listing events,
root_parent_id, and function_ancestry (each with a one-line description and
types where helpful), and keep the brief top description and Returns/Examples if
present in Google style; ensure the function name
relay_events_to_intermediate_steps and parameter names root_parent_id and
function_ancestry are referenced exactly as in the signature.
examples/experimental/claude_code_agent_adapter/src/nat_claude_code_agent_adapter/register.py (1)

376-379: 💤 Low value

Unreachable non-relay CLI branch.

_run_claude_code only routes to _run_claude_code_cli when relay_enabled is true; otherwise it uses the SDK path. As a result the else branch in _run_claude_code_cli (lines 327-328, _build_claude_command) and the non-relay portions of the FileNotFoundError messaging are dead code. Either wire up a CLI fallback for the non-relay case or drop the unused branch to avoid confusion.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@examples/experimental/claude_code_agent_adapter/src/nat_claude_code_agent_adapter/register.py`
around lines 376 - 379, The current routing makes the CLI path unreachable
unless config.relay_enabled is true, leaving the else branch in
_run_claude_code_cli and parts of the FileNotFoundError message unused; either
remove the dead CLI fallback code (drop the else branch in _run_claude_code_cli
and related non-relay FileNotFoundError text) or add a clear CLI fallback path
by updating _run_claude_code to call _run_claude_code_cli when relay is disabled
(or when a new config flag indicates CLI mode), and ensure _build_claude_command
is invoked only in the supported branch; modify the logic in _run_claude_code,
_run_claude_code_cli, and any FileNotFoundError messaging accordingly so there
is no dead-code path left.
examples/experimental/openclaw_agent_adapter/README.md (1)

58-58: 💤 Low value

Avoid possessive 's with inanimate objects (doc style).

"OpenClaw's plugin system" (and "the example's ..." on Line 308) use possessive 's with inanimate nouns. Reword, e.g. "the plugin system of OpenClaw" / "the example settings".

As per coding guidelines: "Documentation in Markdown files should not contain usage of a possessive 's with inanimate objects."

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@examples/experimental/openclaw_agent_adapter/README.md` at line 58, Replace
possessive "'s" usages with "of" phrasing for inanimate nouns: change
"OpenClaw's plugin system" to "the plugin system of OpenClaw" and "the example's
..." to "the example settings" (or "settings of the example") in the README
content; search for and update any other occurrences of possessive "'s" applied
to inanimate objects so documentation follows the style guideline.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@examples/experimental/claude_code_agent_adapter/pyproject.toml`:
- Around line 27-45: Add the example to the root project examples list and
rename the uv source to a nat_-prefixed name: in root pyproject.toml include
"nat_claude_code_agent_adapter" in the examples/installable examples array so
the example is packaged, and in
examples/experimental/claude_code_agent_adapter/pyproject.toml change the
[tool.uv.sources] key from "nvidia-nat" to a nat_-prefixed identifier (e.g.,
"nat_nvidia_nat" or "nat_nvidia-nat") so the source reads like nat_nvidia_nat =
{ path = "../../..", editable = true }; leave the project.name and the entry
point nat_claude_code_agent_adapter = "nat_claude_code_agent_adapter.register"
intact.

In `@examples/experimental/codex_agent_adapter/package.json`:
- Around line 4-6: Update the dependency declaration for `@openai/codex-sdk` in
package.json to pin it to the tested version/range instead of "latest" — replace
the current "`@openai/codex-sdk`": "latest" entry with a stable version (e.g.,
"`@openai/codex-sdk`": "0.135.0" or a constrained range "`@openai/codex-sdk`":
"^0.135.0") so installs align with the package-lock.json and the README's
supported Codex version.

In `@examples/experimental/codex_agent_adapter/pyproject.toml`:
- Around line 30-47: The root pyproject.toml needs the new example registered:
add "nat_codex_agent_adapter" to the top-level examples = [...] array and add a
corresponding [tool.uv.sources] entry named nat_codex_agent_adapter that points
to the example path (nat_codex_agent_adapter = { path =
"examples/experimental/codex_agent_adapter", editable = true }) so the package
declared as name = "nat_codex_agent_adapter" and the entry point nat.components
-> nat_codex_agent_adapter = "nat_codex_agent_adapter.register" in the example
pyproject.toml is discoverable by the root build/configuration.

In
`@examples/experimental/codex_agent_adapter/src/nat_codex_agent_adapter/register.py`:
- Around line 397-400: The `_run_codex_cli` implementation contains a dead
non-relay branch (the `else: command = _build_codex_command(...)` path) that is
never used because `_run_codex` only calls `_run_codex_cli` when
`config.relay_enabled` is true and all non-relay calls go to `_run_node_sdk`;
remove the unreachable branch (and the helper `_build_codex_command` if it
becomes unused) or, if you intended to support non-relay CLI execution, change
`_run_codex` to route non-relay calls into `_run_codex_cli`. Also update the
`FileNotFoundError` handler wording inside `_run_codex_cli` to refer
specifically to the Codex relay binary (and remove “Codex CLI” wording) so the
error message matches the actual execution path. Ensure any removed helper
references (e.g., `_build_codex_command`) are cleaned up and tests/usage updated
accordingly.

In `@examples/experimental/cursor_agent_adapter/pyproject.toml`:
- Around line 27-44: Add the missing example registration: update the root
pyproject.toml to include "nat_cursor_agent_adapter" in the top-level examples =
[...] list, and add a corresponding entry under [tool.uv.sources] named
nat_cursor_agent_adapter that maps the package name to the example package
(using editable = true) so the nat_cursor_agent_adapter component and its
entry-point (nat_cursor_agent_adapter = "nat_cursor_agent_adapter.register") are
discoverable and installable.

In `@examples/experimental/cursor_agent_adapter/README.md`:
- Line 150: The phrase "Relay's raw event file" in README.md uses a possessive
's on an inanimate object; update the sentence to use a non-possessive form such
as "the raw Relay event file" (or "Relay raw event file") so the documentation
follows the guideline against using possessive 's with inanimate objects; search
for the exact string "Relay's raw event file" and replace it accordingly in the
README.md content.

In `@examples/experimental/hermes_agent_adapter/configs/config-relay.yml`:
- Around line 4-11: The config currently enables relay (workflow._type:
hermes_agent, relay_enabled: true) but does not set relay_atof_output_dir, so
ATOF events are written to a temp dir and removed; update the config to set
relay_atof_output_dir to the README's inspect path (e.g.
.tmp/nat-relay-hermes-atof) so the events.jsonl file is preserved for the `cat
./.tmp/nat-relay-hermes-atof/events.jsonl` step, or alternatively change the
README to point to the phoenix config that already sets relay_atof_output_dir.

In `@examples/experimental/hermes_agent_adapter/pyproject.toml`:
- Around line 27-44: The root pyproject.toml must include the example module and
a uv source for nat_hermes_agent_adapter; add "nat_hermes_agent_adapter" to the
root examples array and add a [tool.uv.sources] entry mapping
nat_hermes_agent_adapter to the examples/experimental/hermes_agent_adapter path
(editable true) so the project name nat_hermes_agent_adapter and its existing
[tool.uv.sources] usage in the example match the root config.

In `@examples/experimental/hermes_agent_adapter/README.md`:
- Line 126: The sentence "You can inspect Relay's raw event file:" uses a
possessive 's with an inanimate object; update the README line that currently
reads "You can inspect Relay's raw event file:" (search for that exact string)
to a non-possessive phrasing such as "You can inspect the raw event file of
Relay:" or "You can inspect the Relay raw event file:" to comply with the
documentation guideline.

In
`@examples/experimental/openclaw_agent_adapter/src/nat_openclaw_agent_adapter/register.py`:
- Around line 273-274: The public workflow function openclaw_agent (decorated
with `@register_function` and accepting config: OpenClawAgentWorkflowConfig and
_builder: Builder) must include a return type hint and a Google-style docstring;
update the signature to add the appropriate return type (e.g., ->
YourReturnType) and add a docstring immediately below the def that documents
Args (config, _builder) and Returns (describe return value and type), mentioning
any side effects or exceptions as needed so the function complies with public
API guidelines.

In `@packages/nvidia_nat_core/src/nat/experimental/relay_telemetry_bridge.py`:
- Around line 52-63: The loader load_atof_jsonl currently calls json.loads on
every non-empty line and will raise on a malformed line; change it to open the
file with encoding="utf-8" and wrap the json.loads call in a try/except (catch
json.JSONDecodeError/ValueError) so malformed lines are skipped (optionally log
or count them) and valid dict events continue to be appended to the events list;
keep the function signature and return type the same and only alter the file
open call and the per-line parsing logic in load_atof_jsonl.

---

Nitpick comments:
In
`@examples/experimental/claude_code_agent_adapter/src/nat_claude_code_agent_adapter/register.py`:
- Around line 376-379: The current routing makes the CLI path unreachable unless
config.relay_enabled is true, leaving the else branch in _run_claude_code_cli
and parts of the FileNotFoundError message unused; either remove the dead CLI
fallback code (drop the else branch in _run_claude_code_cli and related
non-relay FileNotFoundError text) or add a clear CLI fallback path by updating
_run_claude_code to call _run_claude_code_cli when relay is disabled (or when a
new config flag indicates CLI mode), and ensure _build_claude_command is invoked
only in the supported branch; modify the logic in _run_claude_code,
_run_claude_code_cli, and any FileNotFoundError messaging accordingly so there
is no dead-code path left.

In `@examples/experimental/openclaw_agent_adapter/README.md`:
- Line 58: Replace possessive "'s" usages with "of" phrasing for inanimate
nouns: change "OpenClaw's plugin system" to "the plugin system of OpenClaw" and
"the example's ..." to "the example settings" (or "settings of the example") in
the README content; search for and update any other occurrences of possessive
"'s" applied to inanimate objects so documentation follows the style guideline.

In `@packages/nvidia_nat_core/src/nat/experimental/relay_telemetry_bridge.py`:
- Around line 66-83: The docstring for relay_events_to_intermediate_steps uses
NumPy-style Parameters/---------- formatting; update it to a Google-style
docstring: replace the Parameters section with an Args: block listing events,
root_parent_id, and function_ancestry (each with a one-line description and
types where helpful), and keep the brief top description and Returns/Examples if
present in Google style; ensure the function name
relay_events_to_intermediate_steps and parameter names root_parent_id and
function_ancestry are referenced exactly as in the signature.

In
`@packages/nvidia_nat_core/tests/nat/experimental/test_relay_telemetry_bridge.py`:
- Around line 124-145: Add a negative-path test that writes a JSONL file
containing both a valid event and a malformed/partial line, then call
load_atof_jsonl and inject_atof_jsonl to verify the loader skips the bad line
and only returns/injects the valid event: create a file with one well-formed
event JSON and one broken line, assert load_atof_jsonl(path) returns only the
valid event, subscribe to Context.intermediate_step_manager, call
inject_atof_jsonl(path, context=...), and assert the captured
IntermediateStep(s) correspond only to the valid event (check event types,
parent_id, and count).
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: 7ef97f18-5301-4c0a-a9da-a9545b40d66b

📥 Commits

Reviewing files that changed from the base of the PR and between ff245d6 and 9165fe4.

⛔ Files ignored due to path filters (10)
  • docs/source/_static/claude_code_agent_adapter/phoenix-relay-trace.png is excluded by !**/*.png
  • docs/source/_static/codex_agent_adapter/phoenix-relay-trace.png is excluded by !**/*.png
  • docs/source/_static/cursor_agent_adapter/phoenix-relay-trace.png is excluded by !**/*.png
  • docs/source/_static/hermes_agent_adapter/phoenix-relay-trace.png is excluded by !**/*.png
  • examples/experimental/claude_code_agent_adapter/uv.lock is excluded by !**/*.lock
  • examples/experimental/codex_agent_adapter/package-lock.json is excluded by !**/package-lock.json
  • examples/experimental/codex_agent_adapter/uv.lock is excluded by !**/*.lock
  • examples/experimental/cursor_agent_adapter/uv.lock is excluded by !**/*.lock
  • examples/experimental/hermes_agent_adapter/uv.lock is excluded by !**/*.lock
  • examples/experimental/openclaw_agent_adapter/uv.lock is excluded by !**/*.lock
📒 Files selected for processing (46)
  • .gitignore
  • examples/README.md
  • examples/experimental/claude_code_agent_adapter/README.md
  • examples/experimental/claude_code_agent_adapter/configs/config-relay-phoenix-eval.yml
  • examples/experimental/claude_code_agent_adapter/configs/config-relay-phoenix.yml
  • examples/experimental/claude_code_agent_adapter/configs/config-relay.yml
  • examples/experimental/claude_code_agent_adapter/data/eval-smoke.json
  • examples/experimental/claude_code_agent_adapter/pyproject.toml
  • examples/experimental/claude_code_agent_adapter/src/nat_claude_code_agent_adapter/__init__.py
  • examples/experimental/claude_code_agent_adapter/src/nat_claude_code_agent_adapter/register.py
  • examples/experimental/codex_agent_adapter/README.md
  • examples/experimental/codex_agent_adapter/configs/config-relay-phoenix-eval.yml
  • examples/experimental/codex_agent_adapter/configs/config-relay-phoenix.yml
  • examples/experimental/codex_agent_adapter/configs/config-relay.yml
  • examples/experimental/codex_agent_adapter/data/eval-smoke.json
  • examples/experimental/codex_agent_adapter/package.json
  • examples/experimental/codex_agent_adapter/pyproject.toml
  • examples/experimental/codex_agent_adapter/src/nat_codex_agent_adapter/__init__.py
  • examples/experimental/codex_agent_adapter/src/nat_codex_agent_adapter/codex_sdk_runner.mjs
  • examples/experimental/codex_agent_adapter/src/nat_codex_agent_adapter/register.py
  • examples/experimental/cursor_agent_adapter/README.md
  • examples/experimental/cursor_agent_adapter/configs/config-relay-phoenix-eval.yml
  • examples/experimental/cursor_agent_adapter/configs/config-relay-phoenix.yml
  • examples/experimental/cursor_agent_adapter/configs/config-relay.yml
  • examples/experimental/cursor_agent_adapter/data/eval-smoke.json
  • examples/experimental/cursor_agent_adapter/pyproject.toml
  • examples/experimental/cursor_agent_adapter/src/nat_cursor_agent_adapter/__init__.py
  • examples/experimental/cursor_agent_adapter/src/nat_cursor_agent_adapter/register.py
  • examples/experimental/hermes_agent_adapter/README.md
  • examples/experimental/hermes_agent_adapter/configs/config-relay-phoenix-eval.yml
  • examples/experimental/hermes_agent_adapter/configs/config-relay-phoenix.yml
  • examples/experimental/hermes_agent_adapter/configs/config-relay.yml
  • examples/experimental/hermes_agent_adapter/data/eval-smoke.json
  • examples/experimental/hermes_agent_adapter/pyproject.toml
  • examples/experimental/hermes_agent_adapter/src/nat_hermes_agent_adapter/__init__.py
  • examples/experimental/hermes_agent_adapter/src/nat_hermes_agent_adapter/register.py
  • examples/experimental/openclaw_agent_adapter/README.md
  • examples/experimental/openclaw_agent_adapter/configs/config-relay-phoenix-eval.yml
  • examples/experimental/openclaw_agent_adapter/configs/config-relay-phoenix.yml
  • examples/experimental/openclaw_agent_adapter/configs/config-relay.yml
  • examples/experimental/openclaw_agent_adapter/data/eval-smoke.json
  • examples/experimental/openclaw_agent_adapter/pyproject.toml
  • examples/experimental/openclaw_agent_adapter/src/nat_openclaw_agent_adapter/__init__.py
  • examples/experimental/openclaw_agent_adapter/src/nat_openclaw_agent_adapter/register.py
  • packages/nvidia_nat_core/src/nat/experimental/relay_telemetry_bridge.py
  • packages/nvidia_nat_core/tests/nat/experimental/test_relay_telemetry_bridge.py

Comment thread examples/experimental/claude_code_agent_adapter/pyproject.toml
Comment thread examples/experimental/codex_agent_adapter/package.json Outdated
Comment thread examples/experimental/codex_agent_adapter/pyproject.toml
Comment thread examples/experimental/codex_agent_adapter/src/nat_codex_agent_adapter/register.py Outdated
Comment thread examples/experimental/cursor_agent_adapter/pyproject.toml
Comment thread examples/experimental/hermes_agent_adapter/configs/config-relay.yml
Comment thread examples/experimental/hermes_agent_adapter/pyproject.toml
Comment thread examples/experimental/hermes_agent_adapter/README.md Outdated
Signed-off-by: Yuchen Zhang <yuchenz@nvidia.com>
Signed-off-by: Yuchen Zhang <yuchenz@nvidia.com>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
pyproject.toml (1)

129-180: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Missing OpenClaw root wiring in examples and tool.uv.sources.

The new adapter set is incomplete here: nat_openclaw_agent_adapter is missing from both the top-level examples list and [tool.uv.sources], even though the experimental examples index includes OpenClaw. This can leave one adapter undiscoverable via the same root example install flow as the others.

Suggested patch
 [tool.setuptools_dynamic_dependencies.optional-dependencies]
 examples = [
   "nat_adk_demo",
@@
   "nat_multi_frameworks",
   "nat_notebooks",
+  "nat_openclaw_agent_adapter",
   "nat_parallel_executor",
@@
 [tool.uv.sources]
 # Examples
 nat_adk_demo = { path = "examples/frameworks/adk_demo", editable = true }
@@
 nat_multi_frameworks = { path = "examples/frameworks/multi_frameworks", editable = true }
 nat_notebooks = { path = "examples/notebooks", editable = true }
+nat_openclaw_agent_adapter = { path = "examples/experimental/openclaw_agent_adapter", editable = true }
 nat_parallel_executor = { path = "examples/control_flow/parallel_executor", editable = true }

Also applies to: 233-322

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pyproject.toml` around lines 129 - 180, The examples and UV source roots are
missing the new OpenClaw adapter; add "nat_openclaw_agent_adapter" to the
top-level examples array (the examples list shown) and also add the
corresponding "nat_openclaw_agent_adapter" entry under the [tool.uv.sources]
section so the adapter is discoverable via the same root/example install flow as
the other adapters.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@pyproject.toml`:
- Around line 129-180: The examples and UV source roots are missing the new
OpenClaw adapter; add "nat_openclaw_agent_adapter" to the top-level examples
array (the examples list shown) and also add the corresponding
"nat_openclaw_agent_adapter" entry under the [tool.uv.sources] section so the
adapter is discoverable via the same root/example install flow as the other
adapters.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: bc3e34aa-91fa-4f1d-86e8-e048ac3da75e

📥 Commits

Reviewing files that changed from the base of the PR and between 13c39be and 4ef7a47.

⛔ Files ignored due to path filters (6)
  • examples/experimental/claude_code_agent_adapter/uv.lock is excluded by !**/*.lock
  • examples/experimental/codex_agent_adapter/package-lock.json is excluded by !**/package-lock.json
  • examples/experimental/codex_agent_adapter/uv.lock is excluded by !**/*.lock
  • examples/experimental/cursor_agent_adapter/uv.lock is excluded by !**/*.lock
  • examples/experimental/hermes_agent_adapter/uv.lock is excluded by !**/*.lock
  • uv.lock is excluded by !**/*.lock
📒 Files selected for processing (9)
  • examples/experimental/codex_agent_adapter/package.json
  • examples/experimental/codex_agent_adapter/src/nat_codex_agent_adapter/register.py
  • examples/experimental/cursor_agent_adapter/README.md
  • examples/experimental/hermes_agent_adapter/README.md
  • examples/experimental/hermes_agent_adapter/configs/config-relay.yml
  • examples/experimental/openclaw_agent_adapter/src/nat_openclaw_agent_adapter/register.py
  • packages/nvidia_nat_core/src/nat/experimental/relay_telemetry_bridge.py
  • packages/nvidia_nat_core/tests/nat/experimental/test_relay_telemetry_bridge.py
  • pyproject.toml
✅ Files skipped from review due to trivial changes (2)
  • examples/experimental/cursor_agent_adapter/README.md
  • examples/experimental/hermes_agent_adapter/README.md
🚧 Files skipped from review as they are similar to previous changes (4)
  • examples/experimental/codex_agent_adapter/package.json
  • examples/experimental/hermes_agent_adapter/configs/config-relay.yml
  • examples/experimental/openclaw_agent_adapter/src/nat_openclaw_agent_adapter/register.py
  • packages/nvidia_nat_core/src/nat/experimental/relay_telemetry_bridge.py

Signed-off-by: Yuchen Zhang <yuchenz@nvidia.com>
Signed-off-by: Yuchen Zhang <yuchenz@nvidia.com>
Signed-off-by: Yuchen Zhang <yuchenz@nvidia.com>
Signed-off-by: Yuchen Zhang <yuchenz@nvidia.com>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (5)
examples/experimental/codex_agent_adapter/src/nat_codex_agent_adapter/register.py (2)

225-247: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Check working_directory before relying on the FileNotFoundError handler.

create_subprocess_exec(..., cwd=...) also raises FileNotFoundError for a missing workspace, so this branch currently reports a bad working_directory as a missing Relay binary. Validating the directory up front will avoid a very misleading failure mode.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@examples/experimental/codex_agent_adapter/src/nat_codex_agent_adapter/register.py`
around lines 225 - 247, The FileNotFoundError from
asyncio.create_subprocess_exec can come from a missing working directory, so in
_run_codex_cli validate cwd (from Path(config.working_directory).resolve())
exists and is a directory before calling create_subprocess_exec; if it does not
exist raise a clear RuntimeError about the invalid working_directory (and still
cleanup relay_temp_dir) instead of falling through to the subprocess
FileNotFoundError handler that assumes the relay binary is missing. Ensure the
check uses the same cwd variable and keep relay_temp_dir.cleanup() on error
paths.

172-175: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Preserve argv boundaries when writing the Relay command.

This uses " ".join(...) to serialize the executable plus args into config.toml, which breaks as soon as any configured path or argument contains whitespace. Please quote/escape the argv list before handing it to Relay.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@examples/experimental/codex_agent_adapter/src/nat_codex_agent_adapter/register.py`
around lines 172 - 175, The code in _write_relay_config currently flattens argv
with " ".join, losing argument boundaries; instead build the argv list and
serialize it (e.g., JSON/TOML array) so spaces are preserved: construct args =
[config.command, *config.command_args, *_build_codex_root_args(config)] and
write that serialized list into the TOML (use json.dumps(args) or a TOML array
representation) when calling path.write_text; update references to
config.command, config.command_args and _build_codex_root_args to use the list
form rather than a joined string.
examples/experimental/hermes_agent_adapter/src/nat_hermes_agent_adapter/register.py (1)

141-144: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Serialize the Relay command with proper quoting.

The current " ".join(...) drops argv boundaries, so whitespace-bearing paths or launcher arguments are persisted incorrectly into config.toml. That is especially risky here because this adapter explicitly encourages launcher wrappers in command_args.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@examples/experimental/hermes_agent_adapter/src/nat_hermes_agent_adapter/register.py`
around lines 141 - 144, The current _write_relay_config builds hermes_command
with " ".join(...) which flattens argv boundaries and loses quoting for
whitespace-bearing paths; instead serialize the command as an array to preserve
each argv element. Update _write_relay_config (referencing
HermesAgentWorkflowConfig, config.command and config.command_args, and
Path.write_text) to write the command field as a JSON array (i.e.,
json.dumps([config.command, *config.command_args])) into the TOML snippet so
each argument is preserved exactly.
examples/experimental/claude_code_agent_adapter/src/nat_claude_code_agent_adapter/register.py (1)

167-170: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Shell-escape the Relay command string.

command and command_args are flattened with a plain " ".join(...), so any absolute path or launcher arg containing spaces/quotes is re-tokenized incorrectly in config.toml. That breaks a valid configuration shape that this adapter explicitly supports.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@examples/experimental/claude_code_agent_adapter/src/nat_claude_code_agent_adapter/register.py`
around lines 167 - 170, The current _write_relay_config flattens
ClaudeCodeAgentWorkflowConfig.command and .command_args using " ".join which
re-tokenizes paths with spaces/quotes; instead import shlex and build the full
argv list ([config.command] + config.command_args) and use shlex.join(...) to
produce a properly shell-escaped command string before json.dumps and
path.write_text; update the function _write_relay_config to use shlex.join on
that argv list (and add the shlex import) so path.write_text writes a safe,
quoted command to the TOML.
examples/experimental/cursor_agent_adapter/src/nat_cursor_agent_adapter/register.py (1)

159-163: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Quote the configured command before persisting it to Relay config.

A plain " ".join(...) loses the original argv boundaries, so valid command/command_args values with spaces are serialized incorrectly. This makes the advertised absolute-path/launcher configuration brittle.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@examples/experimental/cursor_agent_adapter/src/nat_cursor_agent_adapter/register.py`
around lines 159 - 163, The current _write_relay_config function flattens argv
with " ".join which loses argument boundaries; instead serialize the command as
a JSON array to preserve argv. Replace cursor_command = "
".join([config.command, *config.command_args]) with using the list
[config.command, *config.command_args] and write it via json.dumps (e.g.,
f"command = {json.dumps([config.command, *config.command_args])}\n") while
keeping patch_restore_hooks written as before; this ensures
CursorAgentWorkflowConfig.command and command_args are preserved exactly in the
Relay config.
🧹 Nitpick comments (4)
examples/experimental/hermes_agent_adapter/src/nat_hermes_agent_adapter/register.py (1)

260-278: ⚡ Quick win

Document and type the exported workflow entrypoint.

hermes_agent is public but still has no docstring or return annotation. As per coding guidelines "All public APIs require Python 3.11+ type hints on parameters and return values" and "Provide Google-style docstrings for every public module, class, function and CLI command".

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@examples/experimental/hermes_agent_adapter/src/nat_hermes_agent_adapter/register.py`
around lines 260 - 278, The public async function hermes_agent lacks a
Google-style docstring and an explicit return type annotation; add a concise
docstring above hermes_agent describing its purpose, parameters (config:
HermesAgentWorkflowConfig, _builder: Builder), and the yielded value, and
annotate its signature with the correct return type (e.g., ->
AsyncGenerator[FunctionInfo, None]) to reflect that it yields a FunctionInfo;
ensure the docstring also briefly documents what _response_fn and _stream_fn do
and what FunctionInfo.create yields so callers and type checkers can understand
the API.
examples/experimental/claude_code_agent_adapter/src/nat_claude_code_agent_adapter/register.py (1)

269-287: ⚡ Quick win

Add the public entrypoint docstring and return annotation.

claude_code_agent is an exported workflow, but it currently has neither a docstring nor an explicit return type. As per coding guidelines "All public APIs require Python 3.11+ type hints on parameters and return values" and "Provide Google-style docstrings for every public module, class, function and CLI command".

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@examples/experimental/claude_code_agent_adapter/src/nat_claude_code_agent_adapter/register.py`
around lines 269 - 287, The public async workflow function claude_code_agent
lacks a Google-style docstring and an explicit return type; add a module-level
docstring if missing and add a Google-style docstring immediately under the
async def claude_code_agent(...) describing purpose, parameters (config:
ClaudeCodeAgentWorkflowConfig, _builder: Builder) and returns. Also add an
explicit return annotation to claude_code_agent such as ->
AsyncGenerator[FunctionInfo, None] (or the project's preferred AsyncGenerator
generic) to reflect that the function yields FunctionInfo; keep existing inner
helpers (_response_fn, _stream_fn) unchanged.
examples/experimental/codex_agent_adapter/src/nat_codex_agent_adapter/register.py (1)

281-299: ⚡ Quick win

Document and annotate the exported workflow function.

codex_agent is a public entrypoint, but it still lacks both a docstring and an explicit return type. As per coding guidelines "All public APIs require Python 3.11+ type hints on parameters and return values" and "Provide Google-style docstrings for every public module, class, function and CLI command".

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@examples/experimental/codex_agent_adapter/src/nat_codex_agent_adapter/register.py`
around lines 281 - 299, Add a Google-style docstring and an explicit return type
to the public async generator function codex_agent: annotate its signature with
an appropriate AsyncGenerator return type (e.g., -> AsyncGenerator[FunctionInfo,
None] or the project's exact FunctionInfo wrapper type) and include a docstring
that briefly describes the workflow's purpose, its parameters (config:
CodexAgentWorkflowConfig, _builder: Builder), and what it yields (FunctionInfo
containing single_fn and stream_fn). Keep the docstring concise and place it
immediately under the def codex_agent(...) line; you do not need to change the
inner helper functions (_response_fn/_stream_fn) unless they are part of the
public API.
examples/experimental/cursor_agent_adapter/src/nat_cursor_agent_adapter/register.py (1)

277-295: ⚡ Quick win

Add the missing public API docs and return type.

cursor_agent is exported, but it has no docstring and no explicit return annotation. As per coding guidelines "All public APIs require Python 3.11+ type hints on parameters and return values" and "Provide Google-style docstrings for every public module, class, function and CLI command".

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@examples/experimental/cursor_agent_adapter/src/nat_cursor_agent_adapter/register.py`
around lines 277 - 295, Add a Google-style docstring to the exported async
generator function cursor_agent describing its purpose, parameters (config:
CursorAgentWorkflowConfig, _builder: Builder), and what it yields (FunctionInfo
instances) using Args and Yields sections; also add an explicit return type
annotation indicating it is an async generator that yields FunctionInfo (e.g.,
-> AsyncGenerator[FunctionInfo, None]) and import AsyncGenerator from typing if
not present so the signature and docs satisfy the public-API guidelines.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In
`@examples/experimental/claude_code_agent_adapter/src/nat_claude_code_agent_adapter/register.py`:
- Around line 213-235: In _run_claude_code_cli validate that
Path(config.working_directory).resolve() exists and is a directory before
creating the subprocess: check cwd.exists() and cwd.is_dir(), call
relay_temp_dir.cleanup() and raise a clear RuntimeError indicating the provided
working_directory is invalid (include the path) so a bad workspace is reported
instead of a FileNotFoundError about the relay/claude command; keep the existing
FileNotFoundError handler for missing executables.

In
`@examples/experimental/cursor_agent_adapter/src/nat_cursor_agent_adapter/register.py`:
- Around line 222-244: The FileNotFoundError except block in _run_cursor_agent
currently conflates a missing working directory with a missing executable;
before attempting asyncio.create_subprocess_exec, validate cwd =
Path(config.working_directory).resolve() (or use Path(config.working_directory)
then resolve only after existence) and raise a clear RuntimeError (and cleanup
relay_temp_dir) if the directory does not exist or is not a directory, so that
the existing except FileNotFoundError only handles missing executable errors
from asyncio.create_subprocess_exec; update the pre-subprocess logic in
_run_cursor_agent to check cwd.exists() and cwd.is_dir() and handle
cleanup/raise accordingly.

In
`@examples/experimental/hermes_agent_adapter/src/nat_hermes_agent_adapter/register.py`:
- Around line 205-227: The FileNotFoundError raised by
asyncio.create_subprocess_exec can be caused by a missing working directory as
well as a missing executable; before calling asyncio.create_subprocess_exec in
_run_hermes_agent, validate that Path(config.working_directory).resolve() (cwd)
exists and is a directory and if not, call relay_temp_dir.cleanup() and raise a
clear RuntimeError that the configured working_directory is invalid (include the
invalid path), keeping the existing FileNotFoundError except-block to handle the
missing executable/uvx case separately.

---

Outside diff comments:
In
`@examples/experimental/claude_code_agent_adapter/src/nat_claude_code_agent_adapter/register.py`:
- Around line 167-170: The current _write_relay_config flattens
ClaudeCodeAgentWorkflowConfig.command and .command_args using " ".join which
re-tokenizes paths with spaces/quotes; instead import shlex and build the full
argv list ([config.command] + config.command_args) and use shlex.join(...) to
produce a properly shell-escaped command string before json.dumps and
path.write_text; update the function _write_relay_config to use shlex.join on
that argv list (and add the shlex import) so path.write_text writes a safe,
quoted command to the TOML.

In
`@examples/experimental/codex_agent_adapter/src/nat_codex_agent_adapter/register.py`:
- Around line 225-247: The FileNotFoundError from asyncio.create_subprocess_exec
can come from a missing working directory, so in _run_codex_cli validate cwd
(from Path(config.working_directory).resolve()) exists and is a directory before
calling create_subprocess_exec; if it does not exist raise a clear RuntimeError
about the invalid working_directory (and still cleanup relay_temp_dir) instead
of falling through to the subprocess FileNotFoundError handler that assumes the
relay binary is missing. Ensure the check uses the same cwd variable and keep
relay_temp_dir.cleanup() on error paths.
- Around line 172-175: The code in _write_relay_config currently flattens argv
with " ".join, losing argument boundaries; instead build the argv list and
serialize it (e.g., JSON/TOML array) so spaces are preserved: construct args =
[config.command, *config.command_args, *_build_codex_root_args(config)] and
write that serialized list into the TOML (use json.dumps(args) or a TOML array
representation) when calling path.write_text; update references to
config.command, config.command_args and _build_codex_root_args to use the list
form rather than a joined string.

In
`@examples/experimental/cursor_agent_adapter/src/nat_cursor_agent_adapter/register.py`:
- Around line 159-163: The current _write_relay_config function flattens argv
with " ".join which loses argument boundaries; instead serialize the command as
a JSON array to preserve argv. Replace cursor_command = "
".join([config.command, *config.command_args]) with using the list
[config.command, *config.command_args] and write it via json.dumps (e.g.,
f"command = {json.dumps([config.command, *config.command_args])}\n") while
keeping patch_restore_hooks written as before; this ensures
CursorAgentWorkflowConfig.command and command_args are preserved exactly in the
Relay config.

In
`@examples/experimental/hermes_agent_adapter/src/nat_hermes_agent_adapter/register.py`:
- Around line 141-144: The current _write_relay_config builds hermes_command
with " ".join(...) which flattens argv boundaries and loses quoting for
whitespace-bearing paths; instead serialize the command as an array to preserve
each argv element. Update _write_relay_config (referencing
HermesAgentWorkflowConfig, config.command and config.command_args, and
Path.write_text) to write the command field as a JSON array (i.e.,
json.dumps([config.command, *config.command_args])) into the TOML snippet so
each argument is preserved exactly.

---

Nitpick comments:
In
`@examples/experimental/claude_code_agent_adapter/src/nat_claude_code_agent_adapter/register.py`:
- Around line 269-287: The public async workflow function claude_code_agent
lacks a Google-style docstring and an explicit return type; add a module-level
docstring if missing and add a Google-style docstring immediately under the
async def claude_code_agent(...) describing purpose, parameters (config:
ClaudeCodeAgentWorkflowConfig, _builder: Builder) and returns. Also add an
explicit return annotation to claude_code_agent such as ->
AsyncGenerator[FunctionInfo, None] (or the project's preferred AsyncGenerator
generic) to reflect that the function yields FunctionInfo; keep existing inner
helpers (_response_fn, _stream_fn) unchanged.

In
`@examples/experimental/codex_agent_adapter/src/nat_codex_agent_adapter/register.py`:
- Around line 281-299: Add a Google-style docstring and an explicit return type
to the public async generator function codex_agent: annotate its signature with
an appropriate AsyncGenerator return type (e.g., -> AsyncGenerator[FunctionInfo,
None] or the project's exact FunctionInfo wrapper type) and include a docstring
that briefly describes the workflow's purpose, its parameters (config:
CodexAgentWorkflowConfig, _builder: Builder), and what it yields (FunctionInfo
containing single_fn and stream_fn). Keep the docstring concise and place it
immediately under the def codex_agent(...) line; you do not need to change the
inner helper functions (_response_fn/_stream_fn) unless they are part of the
public API.

In
`@examples/experimental/cursor_agent_adapter/src/nat_cursor_agent_adapter/register.py`:
- Around line 277-295: Add a Google-style docstring to the exported async
generator function cursor_agent describing its purpose, parameters (config:
CursorAgentWorkflowConfig, _builder: Builder), and what it yields (FunctionInfo
instances) using Args and Yields sections; also add an explicit return type
annotation indicating it is an async generator that yields FunctionInfo (e.g.,
-> AsyncGenerator[FunctionInfo, None]) and import AsyncGenerator from typing if
not present so the signature and docs satisfy the public-API guidelines.

In
`@examples/experimental/hermes_agent_adapter/src/nat_hermes_agent_adapter/register.py`:
- Around line 260-278: The public async function hermes_agent lacks a
Google-style docstring and an explicit return type annotation; add a concise
docstring above hermes_agent describing its purpose, parameters (config:
HermesAgentWorkflowConfig, _builder: Builder), and the yielded value, and
annotate its signature with the correct return type (e.g., ->
AsyncGenerator[FunctionInfo, None]) to reflect that it yields a FunctionInfo;
ensure the docstring also briefly documents what _response_fn and _stream_fn do
and what FunctionInfo.create yields so callers and type checkers can understand
the API.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: 6c35bb85-09be-4c49-a459-858cf0335c87

📥 Commits

Reviewing files that changed from the base of the PR and between 3bfd704 and 32866c2.

📒 Files selected for processing (23)
  • examples/experimental/claude_code_agent_adapter/README.md
  • examples/experimental/claude_code_agent_adapter/configs/config-relay-phoenix-eval.yml
  • examples/experimental/claude_code_agent_adapter/configs/config-relay-phoenix.yml
  • examples/experimental/claude_code_agent_adapter/configs/config-relay.yml
  • examples/experimental/claude_code_agent_adapter/pyproject.toml
  • examples/experimental/claude_code_agent_adapter/src/nat_claude_code_agent_adapter/register.py
  • examples/experimental/codex_agent_adapter/README.md
  • examples/experimental/codex_agent_adapter/configs/config-relay-phoenix-eval.yml
  • examples/experimental/codex_agent_adapter/configs/config-relay-phoenix.yml
  • examples/experimental/codex_agent_adapter/configs/config-relay.yml
  • examples/experimental/codex_agent_adapter/pyproject.toml
  • examples/experimental/codex_agent_adapter/src/nat_codex_agent_adapter/register.py
  • examples/experimental/cursor_agent_adapter/README.md
  • examples/experimental/cursor_agent_adapter/configs/config-relay-phoenix-eval.yml
  • examples/experimental/cursor_agent_adapter/configs/config-relay-phoenix.yml
  • examples/experimental/cursor_agent_adapter/configs/config-relay.yml
  • examples/experimental/cursor_agent_adapter/src/nat_cursor_agent_adapter/register.py
  • examples/experimental/hermes_agent_adapter/README.md
  • examples/experimental/hermes_agent_adapter/configs/config-relay-phoenix-eval.yml
  • examples/experimental/hermes_agent_adapter/configs/config-relay-phoenix.yml
  • examples/experimental/hermes_agent_adapter/configs/config-relay.yml
  • examples/experimental/hermes_agent_adapter/src/nat_hermes_agent_adapter/register.py
  • examples/experimental/openclaw_agent_adapter/README.md
💤 Files with no reviewable changes (10)
  • examples/experimental/hermes_agent_adapter/configs/config-relay.yml
  • examples/experimental/hermes_agent_adapter/configs/config-relay-phoenix-eval.yml
  • examples/experimental/claude_code_agent_adapter/configs/config-relay.yml
  • examples/experimental/hermes_agent_adapter/configs/config-relay-phoenix.yml
  • examples/experimental/claude_code_agent_adapter/pyproject.toml
  • examples/experimental/cursor_agent_adapter/configs/config-relay.yml
  • examples/experimental/cursor_agent_adapter/configs/config-relay-phoenix-eval.yml
  • examples/experimental/claude_code_agent_adapter/configs/config-relay-phoenix-eval.yml
  • examples/experimental/cursor_agent_adapter/configs/config-relay-phoenix.yml
  • examples/experimental/claude_code_agent_adapter/configs/config-relay-phoenix.yml
✅ Files skipped from review due to trivial changes (6)
  • examples/experimental/cursor_agent_adapter/README.md
  • examples/experimental/codex_agent_adapter/configs/config-relay.yml
  • examples/experimental/hermes_agent_adapter/README.md
  • examples/experimental/openclaw_agent_adapter/README.md
  • examples/experimental/codex_agent_adapter/README.md
  • examples/experimental/claude_code_agent_adapter/README.md
🚧 Files skipped from review as they are similar to previous changes (2)
  • examples/experimental/codex_agent_adapter/configs/config-relay-phoenix-eval.yml
  • examples/experimental/codex_agent_adapter/configs/config-relay-phoenix.yml

Signed-off-by: Yuchen Zhang <yuchenz@nvidia.com>
Signed-off-by: Yuchen Zhang <yuchenz@nvidia.com>
Signed-off-by: Yuchen Zhang <yuchenz@nvidia.com>
Comment thread examples/experimental/openclaw_agent_adapter/README.md Outdated
Comment thread examples/README.md Outdated
Signed-off-by: Yuchen Zhang <yuchenz@nvidia.com>
Signed-off-by: Yuchen Zhang <yuchenz@nvidia.com>

@mnajafian-nv mnajafian-nv left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM with one inline nit :) great work!

@Salonijain27 Salonijain27 left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approved from a dependency point of view

yczhang-nv added 10 commits June 4, 2026 11:00
Signed-off-by: Yuchen Zhang <yuchenz@nvidia.com>
Signed-off-by: Yuchen Zhang <yuchenz@nvidia.com>
Signed-off-by: Yuchen Zhang <yuchenz@nvidia.com>
Signed-off-by: Yuchen Zhang <yuchenz@nvidia.com>
Signed-off-by: Yuchen Zhang <yuchenz@nvidia.com>
Signed-off-by: Yuchen Zhang <yuchenz@nvidia.com>
Signed-off-by: Yuchen Zhang <yuchenz@nvidia.com>
Signed-off-by: Yuchen Zhang <yuchenz@nvidia.com>
Signed-off-by: Yuchen Zhang <yuchenz@nvidia.com>
Signed-off-by: Yuchen Zhang <yuchenz@nvidia.com>
@yczhang-nv yczhang-nv force-pushed the codex/nat-292-code-agent-adapter branch from 04ed0a4 to a2a2569 Compare June 4, 2026 22:16
@yczhang-nv

Copy link
Copy Markdown
Contributor Author

/merge

@rapids-bot rapids-bot Bot merged commit fb8b752 into NVIDIA:develop Jun 4, 2026
28 checks passed
@yczhang-nv yczhang-nv deleted the codex/nat-292-code-agent-adapter branch June 4, 2026 23:07
copy-pr-bot Bot pushed a commit that referenced this pull request Jun 6, 2026
…ia-ai-endpoints bump

The uv.lock files for the experimental coding-agent adapters (added in #1995) still pinned langchain-nvidia-ai-endpoints>=1.3.0,<2.0.0. #1995 merged after #2002 bumped that dependency to >=1.4.1,<2.0.0 in nvidia_nat_langchain, but its branch was locked against the pre-bump state, so the lockfiles were never regenerated. This left the uv-lock-all-pyprojects pre-commit hook failing on any full run. Re-locked with uv 0.9.28 to match CI.

Signed-off-by: Zhongxuan Wang <daniewang@nvidia.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

feature request New feature or request non-breaking Non-breaking change

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants